﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Autofac;
using ComputerVision.ANN;
using ComputerVision.BaseForm;
using ComputerVision.Common;
using ComputerVision.Data;
using ComputerVision.Services;
using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Drawing;

namespace ComputerVision
{
    public partial class frmXeVao : frmObject
    {
        private readonly IService<ConfigrationCamera> _configCamera;
        private readonly IService<LoaiXe> _loaiXe;
        private readonly IService<Xe> _xe;
        private readonly IService<VeXe> _veXe;

        private readonly ImageProcess _process;
        //Camera sau
        private Capture _cap0;
        //Camera truoc
        private Capture _cap1;
        private int _cmr0;
        private int _cmr1;
        private Image<Bgr, byte> _img1;
        private Bitmap _img1End;
        private Image<Bgr, byte> _img0;
        private Bitmap _img0End;
        //nhận diện mặt người vào
        //private Image<Bgr, byte> img3 = null;
        //nhận diện mặt người ra
        private Image<Gray, byte> _imgGray1;
        private readonly Image<Bgr, Byte> _biensoxevao;
        private bool validCard;
        //private Image<Bgr, Byte> _biensoxevaoEnd;
        private string bienso;
        private string _computerName;
        private string _soVe;

        private System.Text.RegularExpressions.Regex regex =
            new System.Text.RegularExpressions.Regex("\\d\\d-[A-Z][0-9A-Z]-\\d{4,5}");

        private System.Text.RegularExpressions.Regex regexoto =
            new System.Text.RegularExpressions.Regex("\\d\\d-[A-Z]-\\d{4,5}");

        public frmXeVao(Image<Bgr, byte> biensoxevao)
        {
            _biensoxevao = biensoxevao;
            InitializeComponent();
            _computerName = Environment.MachineName;
            _configCamera = Program.Container.Resolve<IService<ConfigrationCamera>>();
            _loaiXe = Program.Container.Resolve<IService<LoaiXe>>();
            _xe = Program.Container.Resolve<IService<Xe>>();
            _veXe = Program.Container.Resolve<IService<VeXe>>();
            _process = new ImageProcess();
            _soVe = txtSoVe.Text;
            GetConfigCamera(_computerName);
            LoadLoaiXe();
        }

        /// <summary>
        /// Get data from devices
        /// </summary>
        private void CaptureWc()
        {
            //Camera sau
            _cap0 = new Capture(_cmr0);
            _cap0.ImageGrabbed += wc0;
            _cap0.Start();
            //Camera trước
            _cap1 = new Capture(_cmr1);
            _cap1.ImageGrabbed += Wc1DetectFace;
            _cap1.Start();
        }

        private void Wc1DetectFace(object sender, EventArgs e)
        {
            try
            {
                var faceDetector1 = new CascadeClassifier("haarcascade_frontalface_default.xml");
                _img1 = _cap1.RetrieveBgrFrame();
                _imgGray1 = _img1.Convert<Gray, byte>();
                foreach (var face in faceDetector1.DetectMultiScale(_imgGray1, 1.1, 10, new Size(20, 20), Size.Empty))
                {
                    _img1.Draw(face, new Bgr(Color.White), 1);
                }
                picTruoc.Image = _img1.Bitmap;
            }
            catch (Exception ex)
            {

            }
        }

        private void wc0(object sender, EventArgs e)
        {
            try
            {
                _img0 = _cap0.RetrieveBgrFrame();
                picSau.Image = _img0.Bitmap;
            }
            catch (Exception ex)
            {

            }
        }

        private void frmXeVao_Load(object sender, EventArgs e)
        {
            CaptureWc();
            Save();
        }
        int i;
        int[] j = { 0, -1, -3, -4, -5, -6, -8, 1, 2, 4, 5, 6, 8 };
        private void Timer_Vao_Tick(object sender, EventArgs e)
        {
            //cứ 100 mili giây đọc biển số xe vào 1 lần cho đến khi đúng định dạng biển số thì ngưng
            //_biensoxevao = new Image<Bgr, Byte>(_img0.Bitmap);
            //   bienso = _process.docbienso(_biensoxevao, picBiensovao, neuralNetwork, neuralNetwork2);
            bienso = _process.docbienso(_biensoxevao.Rotate(j[i], new Bgr(0, 0, 0)), picBiensovao, neuralNetwork, neuralNetwork2);

            if (regex.IsMatch(bienso))
            {
                Timer_Vao.Enabled = false;
                _img0End = _img0.ToBitmap();
                _img1End = _img1.ToBitmap();
                txtBiensovao.Text = bienso;
                i = 0;
                foreach (LoaiXe loaiXe in cbLoaixe.Items)
                {
                    if (loaiXe.Ten.ToUpper().Equals(Constants.Xe.XeMay.ToUpper()))
                    {
                        cbLoaixe.SelectedItem = loaiXe;
                        break;
                    }
                }

                lblTrangThaiDoc.Text = Constants.StatusReading.Stopped;
                lblTrangThaiDoc.ForeColor = Color.Red;
                btnDocLai.Text = @"Đọc tiếp";

            }
            else if (regexoto.IsMatch(bienso))
            {
                Timer_Vao.Enabled = false;
                _img0End = _img0.ToBitmap();
                _img1End = _img1.ToBitmap();
                txtBiensovao.Text = bienso;
                foreach (LoaiXe loaiXe in cbLoaixe.Items)
                {
                    if (loaiXe.Ten.ToUpper().Equals(Constants.Xe.Oto.ToUpper()))
                    {
                        cbLoaixe.SelectedItem = loaiXe;
                        break;
                    }
                }

                lblTrangThaiDoc.Text = Constants.StatusReading.Stopped;
                lblTrangThaiDoc.ForeColor = Color.Red;
                btnDocLai.Text = @"Đọc tiếp";
            }
            else
            {
                if (i > 11)
                    i = 11;
                else
                    i = i + 1;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (Timer_Vao.Enabled == false)
            {
                Timer_Vao.Enabled = true;
                //picBiensovao.Image = null;
                btnDocLai.Text = @"Ngừng";
                lblTrangThaiDoc.Text = Constants.StatusReading.Reading;
                lblTrangThaiDoc.ForeColor = Color.Blue;
            }
            else
            {
                Timer_Vao.Enabled = false;
                //picBiensovao.Image = null;
                btnDocLai.Text = @"Đọc tiếp";
                lblTrangThaiDoc.Text = Constants.StatusReading.Stopped;
                lblTrangThaiDoc.ForeColor = Color.Red;
            }
        }

        private void GetConfigCamera(string name)
        {
            var items = _configCamera.ToList().ToList().Where(p => p.ComputerName.Contains(name)).OrderBy(a => a.Name).ToList();

            var item = items.FirstOrDefault(p => p.Name.Contains(Constants.CameraPosition.First));
            if (item != null)
            {
                _cmr1 = (item.DeviceId != null) ? (int)item.DeviceId : 0;
            }

            item = items.FirstOrDefault(p => p.Name.Contains(Constants.CameraPosition.Second));
            if (item != null)
            {
                _cmr0 = (item.DeviceId != null) ? (int)item.DeviceId : 0;

            }
        }

        private void LoadLoaiXe()
        {
            var loaixe = _loaiXe.ToList().ToList();
            foreach (LoaiXe loai in loaixe)
            {
                cbLoaixe.Items.Add(loai);
            }
        }

        #region Validation

        private void ValidCard()
        {
            int result;
            bool flag1;
            bool flag2;

            flag1 = int.TryParse(txtSoVe.Text, out result);
            var soVe = _veXe.Detail(result);
            flag2 = (soVe != null);

            if (flag1 && flag2)
            {
                lblTrangThaiThe.Text = @"Vé hợp lệ";
                lblTrangThaiThe.ForeColor = Color.Blue;
            }
            else
            {
                lblTrangThaiThe.Text = @"Vé không hợp lệ";
                lblTrangThaiThe.ForeColor = Color.Red;
            }
        }

        protected bool Validator()
        {
            if (string.IsNullOrEmpty(txtSoVe.Text))
            {
                AlertList.Error("Bạn chưa nhập số vé. Xin vui lòng kiểm tra lại");
                txtSoVe.Focus();
                return false;
            }

            int result;
            if (!int.TryParse(txtSoVe.Text, out result))
            {
                AlertList.Error("Bạn nhập số vé không hợp lệ. Xin vui lòng kiểm tra lại");
                txtSoVe.Focus();
                return false;
            }

            var soVe = _veXe.Detail(result);
            if (soVe == null)
            {
                AlertList.Error("Bạn nhập số vé không có trong dữ liệu. Xin vui lòng kiểm tra lại");
                txtSoVe.Focus();
                return false;
            }

            if (cbLoaixe.SelectedItem == null)
            {
                AlertList.Error("Bạn chưa chọn loại xe. Xin vui lòng kiểm tra lại");
                cbLoaixe.Focus();
                return false;
            }

            var loaiXe = cbLoaixe.SelectedItem as LoaiXe;

            if (!loaiXe.Ten.ToUpper().Equals(Constants.Xe.XeDap.ToUpper()) && string.IsNullOrEmpty(txtBiensovao.Text))
            {
                AlertList.Error("Bạn chưa nhập biển số xe. Xin vui lòng kiểm tra lại");
                txtBiensovao.Focus();
                return false;
            }

            if (loaiXe.Ten.ToUpper().Equals(Constants.Xe.XeDap.ToUpper()))
            {
                _img0End = _img0.ToBitmap();
                _img1End = _img1.ToBitmap();
            }


            return true;
        }

        #endregion

        #region Insert

        protected void Insert()
        {
            try
            {
                var loaiXe = cbLoaixe.SelectedItem as LoaiXe;
                var model = new Xe
                {
                    Id = Guid.NewGuid(),
                    LoaiXeId = loaiXe.Id,
                    SoVe = int.Parse(txtSoVe.Text),
                    BienSoXe = txtBiensovao.Text.ToUpper(),
                    NgayVao = DateTime.Now,
                    GiaTien = loaiXe.GiaTien,
                    ImgBienXeVao = ImageProcess.ConvertToByteArray(picBiensovao.Image),
                    ImgVaoTruoc = ImageProcess.ConvertToByteArray(_img1End),
                    ImgVaoSau = ImageProcess.ConvertToByteArray(_img0End),
                    Status = true,
                    Created = DateTime.Now,
                    CreatedBy = Constants.CurrentUser,
                    Modified = DateTime.Now,
                    ModifiedBy = Constants.CurrentUser
                };
                _xe.Create(model);

                //Reset controls
                txtSoVe.Text = string.Empty;
                txtBiensovao.Text = string.Empty;
                txtSoVe.Focus();
            }
            catch (Exception ex)
            {
                //AlertList.Error("Lỗi phát sinh khi tạo mới dữ liệu.");
                AlertList.Error(ex.ToString());
            }
        }

        #endregion

        private void btnTiep_Click(object sender, EventArgs e)
        {
            if (Validator())
            {
                Insert();
            }
        }

        private void timerClock_Tick(object sender, EventArgs e)
        {
            dtpGioVao.Value = DateTime.Now;
            dtpNgayvao.Value = DateTime.Now;

            //valid card
            if (!txtSoVe.Text.Trim().Equals(string.Empty) && !txtSoVe.Text.Trim().Equals(_soVe))
            {
                ValidCard();
                _soVe = txtSoVe.Text.Trim();
            }
        }

        private void txtBiensovao_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            txtBiensovao.ReadOnly = false;
            txtBiensovao.SelectAll();
        }

        //Neural Network Object With Output Type String
        private NeuralNetwork<string> neuralNetwork = null;
        private NeuralNetwork<string> neuralNetwork2 = null;
        //Data Members Required For Neural Network
        private Dictionary<string, double[]> TrainingSet;
        private Dictionary<string, double[]> TrainingSet2;
        private int av_ImageHeight;
        private int av_ImageWidth;
        private int NumOfPatterns;
        private int av_ImageHeight2;
        private int av_ImageWidth2;
        private int NumOfPatterns2;
        private void Save()
        {

            string[] Images = Directory.GetFiles(Application.StartupPath + @"\ImageTrainning", "*.bmp");
            NumOfPatterns = Images.Length;
            av_ImageHeight = 0;
            av_ImageWidth = 0;
            foreach (string s in Images)
            {
                var Temp = new Bitmap(s);
                av_ImageHeight += Temp.Height;
                av_ImageWidth += Temp.Width;
                Temp.Dispose();
            }
            av_ImageHeight /= NumOfPatterns;
            av_ImageWidth /= NumOfPatterns;

            int networkInput = av_ImageHeight * av_ImageWidth;
            string[] Images2 = Directory.GetFiles(Application.StartupPath + @"\ImageTrainningDigit", "*.bmp");
            NumOfPatterns2 = Images2.Length;
            av_ImageHeight2 = 0;
            av_ImageWidth2 = 0;
            foreach (string s in Images2)
            {
                var Temp2 = new Bitmap(s);
                av_ImageHeight2 += Temp2.Height;
                av_ImageWidth2 += Temp2.Width;
                Temp2.Dispose();
            }
            av_ImageHeight2 /= NumOfPatterns2;
            av_ImageWidth2 /= NumOfPatterns2;

            int networkInput2 = av_ImageHeight2 * av_ImageWidth2;
            GenerateTrainingSet();
            CreateNeuralNetwork();
        }

        private void CreateNeuralNetwork()
        {
            if (TrainingSet == null)
                throw new Exception("Unable to Create Neural Network As There is No Data to Train..");

            neuralNetwork = new NeuralNetwork<string>
                (new BP3Layer<string>(av_ImageHeight * av_ImageWidth, 295, 98, NumOfPatterns), TrainingSet);

            neuralNetwork.MaximumError = 1.1;
            neuralNetwork.LoadNetwork(Application.StartupPath + @"\ImageTrainning\Model.net");

            neuralNetwork2 = new NeuralNetwork<string>(new BP3Layer<string>(av_ImageHeight2 * av_ImageWidth2, 295, 98, NumOfPatterns2), TrainingSet2);

            neuralNetwork2.MaximumError = 1.1;
            neuralNetwork2.LoadNetwork(Application.StartupPath + @"\ImageTrainningDigit\Digit.net");
        }

        private void GenerateTrainingSet()
        {

            string[] Patterns = Directory.GetFiles(Application.StartupPath + @"\ImageTrainning", "*.bmp");
            TrainingSet = new Dictionary<string, double[]>(Patterns.Length);
            foreach (string s in Patterns)
            {
                var Temp = new Bitmap(s);
                TrainingSet.Add(Path.GetFileNameWithoutExtension(s),
                    ImageProcessing.ToMatrix(Temp, av_ImageHeight, av_ImageWidth));
                Temp.Dispose();
            }

            string[] Patterns2 = Directory.GetFiles(Application.StartupPath + @"\ImageTrainningDigit", "*.bmp");
            TrainingSet2 = new Dictionary<string, double[]>(Patterns2.Length);
            foreach (string s in Patterns2)
            {
                var Temp2 = new Bitmap(s);
                TrainingSet2.Add(Path.GetFileNameWithoutExtension(s),
                    ImageProcessing.ToMatrix(Temp2, av_ImageHeight2, av_ImageWidth2));
                Temp2.Dispose();
            }

        }

        private void txtSoVe_MouseEnter(object sender, EventArgs e)
        {
            txtSoVe.SelectAll();
        }

        private void txtSoVe_MouseDown(object sender, MouseEventArgs e)
        {
            txtSoVe.SelectAll();

        }

        private void txtSoVe_TextChanged(object sender, EventArgs e)
        {
            if (txtSoVe.Text.Length == 10)
            {
                txtSoVe.SelectAll();

            }
        }


    }
}